home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1995…tember: Reference Library / Dev.CD Sep 95 RL / Dev.CD Sep 95 RL.toast / mac / Technical Documentation / develop / develop Issue 20 code / Scripting the Finder / Zawphing / DialogUtilities.cp < prev    next >
Encoding:
Text File  |  1994-10-11  |  33.9 KB  |  1,238 lines  |  [TEXT/MMCC]

  1. /*================================================================================
  2.     DialogUtilities.c
  3.     
  4.     circa 1991 by Greg Anderson
  5.     greggor@apple.com
  6.     
  7.     This file contains various dialog box utility routines
  8. ================================================================================*/
  9. #include "DialogUtilities.h"
  10.  
  11. #include <Types.h>
  12. #include <Errors.h>
  13. #include <Memory.h>
  14. #include <Resources.h>
  15. #include <Quickdraw.h>
  16. #include <Controls.h>
  17. #include <Dialogs.h>
  18. #include <MixedMode.h>
  19.  
  20. #if USESROUTINEDESCRIPTORS
  21.     RoutineDescriptor gDrawDottedLineProcRD = BUILD_ROUTINE_DESCRIPTOR(uppUserItemProcInfo, DrawDottedLineProc);
  22.     RoutineDescriptor gDrawFrameRectProcRD = BUILD_ROUTINE_DESCRIPTOR(uppUserItemProcInfo, DrawFrameRectProc);
  23.     RoutineDescriptor gDrawDefaultProcRD = BUILD_ROUTINE_DESCRIPTOR(uppUserItemProcInfo, DrawDefaultProc);
  24.     RoutineDescriptor gDrawActiveItemProcRD = BUILD_ROUTINE_DESCRIPTOR(uppUserItemProcInfo, DrawActiveItemProc);
  25.     RoutineDescriptor gDrawGreyTransformProcRD = BUILD_ROUTINE_DESCRIPTOR(uppUserItemProcInfo, DrawGreyTransformProc);
  26.     RoutineDescriptor gCutPasteFilterRD = BUILD_ROUTINE_DESCRIPTOR(uppModalFilterProcInfo, CutPasteFilter);
  27. #endif
  28.  
  29. //----------------------------------------------------------------------------------------
  30. // SimpleBox: 
  31. //
  32. // Display a dialog
  33. //----------------------------------------------------------------------------------------
  34. void SimpleBox(short id)
  35. {
  36.     DialogPtr        dlog;
  37.     short            itemHit;
  38.  
  39.     dlog = GetNewDialog( id, (Ptr)0L, (WindowPtr)-1L);
  40.  
  41.     if( dlog != nil )
  42.     {
  43.         SetPort( dlog );
  44.         SelectWindow(dlog);
  45.         InstallDefaultOutline( dlog, 1 );
  46.         CenterAndShowDialog(dlog);
  47.         
  48.         //
  49.         // Wait for user to click "Okay"
  50.         //
  51.         do
  52.         {
  53. #if USESROUTINEDESCRIPTORS
  54.                 ModalDialog((ModalFilterUPP) &gCutPasteFilterRD, &itemHit);
  55. #else
  56.                 ModalDialog((ModalFilterUPP) CutPasteFilter, &itemHit);
  57. #endif
  58.         } while( itemHit != 1 );
  59.         DisposDialog(dlog);
  60.     }
  61.     else
  62.     {
  63.         DebugStr( "\pCouldn't show simple dialog" );
  64.     }
  65. } // SimpleBox 
  66.  
  67. //----------------------------------------------------------------------------------------
  68. // MessageBox: 
  69. //
  70. // Display a message
  71. //----------------------------------------------------------------------------------------
  72. void MessageBox(short id, Str255 pstr)
  73. {
  74.     DialogPtr        dlog;
  75.     short            itemHit;
  76.  
  77.     dlog = GetNewDialog( id, (Ptr)0L, (WindowPtr)-1L);
  78.  
  79.     if( dlog != nil )
  80.     {
  81.         SetPort( dlog );
  82.         ParamText( pstr, nil, nil, nil );
  83.         SelectWindow(dlog);
  84.         InstallDefaultOutline( dlog, 1 );
  85.         CenterAndShowDialog(dlog);
  86.         
  87.         //
  88.         // Wait for user to click "Okay"
  89.         //
  90.         do
  91.         {
  92. #if USESROUTINEDESCRIPTORS
  93.                 ModalDialog((ModalFilterUPP) &gCutPasteFilterRD, &itemHit);
  94. #else
  95.                 ModalDialog((ModalFilterUPP) CutPasteFilter, &itemHit);
  96. #endif
  97.         } while( itemHit != 1 );
  98.         DisposDialog(dlog);
  99.     }
  100.     else
  101.     {
  102.         DebugStr( pstr );
  103.     }
  104. } // MessageBox 
  105.  
  106. //----------------------------------------------------------------------------------------
  107. // CenterDialog: 
  108. //
  109. //    Center the specified dialog box
  110. //    
  111. //    This code centers the dialog box on the main monitor (the one
  112. //    with the menu bar) such that 1/3rd of the empty space left on
  113. //    that screen is above the dialog and 2/3rds of it is below the
  114. //    dialog
  115. //
  116. //    dx and dy allow the dialog to be offset a little, if desired.
  117. //----------------------------------------------------------------------------------------
  118. void CenterDialog(DialogPtr dlog, short dx, short dy)
  119. {
  120.     short            menuHeight;
  121.     short            dlogWidth;
  122.     short            dlogHeight;
  123.     short            scrnWidth;
  124.     short            scrnHeight;
  125.     short            newDlogX;
  126.     short            newDlogY;
  127.     
  128.     //
  129.     // How tall is the menu bar?
  130.     //
  131.     menuHeight = GetMBarHeight();
  132.     
  133.     //
  134.     // Calculate the size of the dialog box and the main screen
  135.     // (without the menu bar)
  136.     //
  137.     dlogWidth    = (dlog->portRect.right - dlog->portRect.left);
  138.     dlogHeight    = (dlog->portRect.bottom - dlog->portRect.top);
  139.     scrnWidth    = (qd.screenBits.bounds.right - qd.screenBits.bounds.left);
  140.     scrnHeight    = (qd.screenBits.bounds.bottom - qd.screenBits.bounds.top) - menuHeight;
  141.     
  142.     //
  143.     // Quick check: don't leave any empty space if the dialog is
  144.     // too large to fit on the main screen.  This sanity check
  145.     // really should not be necessary, though, as all dialog boxes
  146.     // should fit on 9" screens
  147.     //
  148.     if( dlogHeight > scrnHeight)
  149.         dlogHeight = scrnHeight;
  150.         
  151.     //
  152.     // Calculate the menu's new location
  153.     //
  154.     newDlogX = (qd.screenBits.bounds.left + (scrnWidth - dlogWidth) / 2) + dx;
  155.     newDlogY = (qd.screenBits.bounds.top + menuHeight + (scrnHeight - dlogHeight) / 3) + dy;
  156.     
  157.     //
  158.     // Move the dialog and show it
  159.     //
  160.     MoveWindow(dlog,newDlogX,newDlogY,false);
  161. } // CenterDialog
  162.  
  163. //----------------------------------------------------------------------------------------
  164. // CenterAndShowDialog
  165. //----------------------------------------------------------------------------------------
  166. void CenterAndShowDialog(DialogPtr dlog)
  167. {
  168.     CenterDialog(dlog);
  169.     ShowWindow(dlog);
  170. } // CenterAndShowDialog 
  171.  
  172. //----------------------------------------------------------------------------------------
  173. // AddNewUserItem:
  174. //
  175. //    Creates a new useritem in the specified dialog box & returns
  176. //    its item number
  177. //----------------------------------------------------------------------------------------
  178. short AddNewUserItem( DialogPtr dlog )
  179. {
  180.     DialogPeek        theDialog        = (DialogPeek)dlog;
  181.     short**            itemHandle        = (short**)theDialog->items;
  182.     short            nItems            = **itemHandle + 1;
  183.     short            newItem            = 0;
  184.     DITLitem*        ditlPtr;
  185.     Size            itemHandleSize;
  186.     
  187.     itemHandleSize = GetHandleSize( (Handle)itemHandle );
  188.     SetHandleSize( (Handle)itemHandle, itemHandleSize + sizeof(DITLitem) );
  189.     if( MemError() == noErr )
  190.     {
  191.         //
  192.         // We dereference the (potentially) unlocked itemHandle
  193.         // here; don't do any memory-moving calls until we've
  194.         // initialized the new DITL item
  195.         //
  196.         ditlPtr = (DITLitem*) ( (*itemHandle) + (itemHandleSize / sizeof(short)) );
  197.         
  198.         //
  199.         // Fill in the new fields
  200.         //
  201.         ditlPtr->placeholder = 0;
  202.         ditlPtr->itemType = userItem;
  203.         ditlPtr->extraLength = 0;
  204.         
  205.         //
  206.         // Remember / record the new number of items
  207.         //
  208.         newItem = nItems + 1;
  209.         **itemHandle = newItem - 1;
  210.     }
  211.     
  212.     return newItem;
  213. } // AddNewUserItem 
  214.  
  215. //----------------------------------------------------------------------------------------
  216. // DrawDottedLineProc: 
  217. //
  218. // Draw a dotted line; install as the draw proc for a user item.
  219. //----------------------------------------------------------------------------------------
  220. pascal void DrawDottedLineProc(DialogPtr dlog, short item)
  221. {
  222.     short                type;
  223.     Handle                itemHandle;
  224.     Rect                box;
  225.     PenState            saveState;
  226.     Point                lineStart;
  227.     Point                lineEnd;
  228.     
  229.     //
  230.     // Save the drawing mode before doing anything with
  231.     // the pen
  232.     //
  233.     GetPenState( &saveState );
  234.     
  235.     //
  236.     // Get the bounding box of the userItem & set lineStart
  237.     // to the upper left corner and lineEnd to the lower right
  238.     // corner of the bounding rectangle
  239.     //
  240.     GetDItem(dlog, item, &type, (Handle*)&itemHandle, &box);
  241.     lineStart.h = box.left;
  242.     lineStart.v = box.top;
  243.     lineEnd.h = box.right;
  244.     lineEnd.v = box.bottom;
  245.     
  246.     //
  247.     // The line is always drawn along the longer edge
  248.     //
  249.     if( (lineEnd.h - lineStart.h) > (lineEnd.v - lineStart.v) )
  250.         lineEnd.v = lineStart.v;
  251.     else
  252.         lineEnd.h = lineStart.h;
  253.         
  254.     //
  255.     // Set the pen mode and draw the line
  256.     //
  257.     PenNormal();
  258.     PenPat(&qd.gray);
  259.     MoveTo( lineStart.h, lineStart.v );
  260.     LineTo( lineEnd.h, lineEnd.v );
  261.     
  262.     //
  263.     // Restore the pen state
  264.     //
  265.     SetPenState( &saveState );
  266. } // DrawDottedLineProc 
  267.  
  268. //----------------------------------------------------------------------------------------
  269. // SetUserItemToDottedLine: 
  270. //
  271. // Make the given userItem a dotted line
  272. //----------------------------------------------------------------------------------------
  273. void SetUserItemToDottedLine( DialogPtr dlog, short whichItem )
  274. {
  275.     short            type;
  276.     Handle            itemHandle;
  277.     Rect            box;
  278.     
  279.     GetDItem(dlog,whichItem,&type,&itemHandle,&box);
  280. #if USESROUTINEDESCRIPTORS
  281.     SetDItem(dlog,whichItem,type,(Handle)&gDrawDottedLineProcRD,&box);
  282. #else
  283.     SetDItem(dlog,whichItem,type,(Handle)DrawDottedLineProc,&box);
  284. #endif
  285. } // SetUserItemToDottedLine 
  286.  
  287. //----------------------------------------------------------------------------------------
  288. // DrawFrameRectProc: 
  289. //
  290. // Draw a frame around the specified userItem
  291. //----------------------------------------------------------------------------------------
  292. pascal void DrawFrameRectProc(DialogPtr dlog, short item)
  293. {
  294.     short                type;
  295.     Handle                itemHandle;
  296.     Rect                box;
  297.     PenState            saveState;
  298.     
  299.     //
  300.     // Save the drawing mode before doing anything with
  301.     // the pen
  302.     //
  303.     GetPenState( &saveState );
  304.     
  305.     //
  306.     // Get the bounding box of the userItem
  307.     //
  308.     GetDItem(dlog, item, &type, (Handle*)&itemHandle, &box);
  309.     
  310.     //
  311.     // Set the pen mode and draw the box
  312.     //
  313.     PenNormal();
  314.     FrameRect( &box );
  315.     
  316.     //
  317.     // Restore the pen state
  318.     //
  319.     SetPenState( &saveState );
  320. } // DrawFrameRectProc 
  321.  
  322. //----------------------------------------------------------------------------------------
  323. // SetUserItemToFrameRect: 
  324. //
  325. // Make the given user item a simple frame
  326. //----------------------------------------------------------------------------------------
  327. void SetUserItemToFrameRect( DialogPtr dlog, short whichItem )
  328. {
  329.     short            type;
  330.     Handle            itemHandle;
  331.     Rect            box;
  332.     
  333.     GetDItem(dlog,whichItem,&type,&itemHandle,&box);
  334. #if USESROUTINEDESCRIPTORS
  335.     SetDItem(dlog,whichItem,type,(Handle)&gDrawFrameRectProcRD,&box);
  336. #else
  337.     SetDItem(dlog,whichItem,type,(Handle)DrawFrameRectProc,&box);
  338. #endif
  339. } // SetUserItemToFrameRect 
  340.  
  341. //----------------------------------------------------------------------------------------
  342. // DrawDefaultProc:
  343. //
  344. //    Draw the thick rounded rectangle around the default button
  345. //
  346. //    This routine uses Keith Rollin's algorithm, as presented in the
  347. //    USENET Guide to Programming the Macintosh.  I have modified the
  348. //    basic algorithm only slightly--I add two to the calculated
  349. //    'buttonOval' value.  This gets better results, particularly for
  350. //    buttons of the default size (18 points).
  351. //----------------------------------------------------------------------------------------
  352. pascal void DrawDefaultProc(DialogPtr dlog, short item)
  353. {
  354.     short                defaultButton;
  355.     
  356.     //
  357.     // Don't call GetDItem if the default button # has a strange value
  358.     //
  359.     defaultButton = ((DialogPeek)dlog)->aDefItem;
  360.     if( defaultButton > 0 )
  361.     {
  362.         short                type;
  363.         Handle                userHandle;
  364.         Rect                outlineBox;
  365.  
  366.         //
  367.         // Only draw the bold outline around the default button
  368.         // if it really is a button
  369.         //
  370.         GetDItem(dlog, defaultButton, &type, &userHandle, &outlineBox);
  371.         if( (type & (ctrlItem + btnCtrl)) == ctrlItem + btnCtrl )
  372.         {
  373.             PenState            saveState;
  374.             short                buttonOval;
  375.  
  376.             GetPenState( &saveState );
  377.             InsetRect(&outlineBox,-4,-4);
  378.             
  379.             //
  380.             // We want to draw the thick line with a normal
  381.             // pen pattern that is 3 pixels wide
  382.             //
  383.             PenNormal();
  384.             PenSize(3,3);
  385.             PenMode(srcCopy);
  386.             
  387.             //
  388.             // If the button we are outlining is disabled,
  389.             // draw the outline with a gray pattern.
  390.             //
  391.             if( !DialogItemEnabled(dlog, defaultButton ) )
  392.             {
  393.                 PenPat(&qd.gray);
  394.             }
  395.             
  396.             //
  397.             // Calculate the curvature to use and draw the thick line
  398.             //
  399.             buttonOval = 2 + (outlineBox.bottom - outlineBox.top) / 2;
  400.             FrameRoundRect(&outlineBox,buttonOval,buttonOval);
  401.             
  402.             SetPenState( &saveState );
  403.         }
  404.     }
  405. } // DrawDefaultProc 
  406.  
  407. //----------------------------------------------------------------------------------------
  408. // InstallDefaultOutline: 
  409. //
  410. //    This function creates a useritem around the default button &
  411. //    installs a drawing proc that draws the default border around it.
  412. //    
  413. //    If you want a button other than button #1 to act as the default
  414. //    button, don't forget to supply your own filterProc that
  415. //    translates Return to the correct item number.  If you use the
  416. //    CutPasteFilter implemented in this file, Return and Enter will
  417. //    be translated to be equivalent to clicking on the button that
  418. //    has the default outline around it.
  419. //----------------------------------------------------------------------------------------
  420. short InstallDefaultOutline(DialogPtr dlog, short button)
  421. {
  422.     short            userItem;
  423.     short            type;
  424.     Handle            item;
  425.     Rect            box;
  426.     Rect            userBox;
  427.     
  428.     ((DialogPeek)dlog)->aDefItem = button;
  429.     userItem = AddNewUserItem( dlog );
  430.     if( userItem > 0 )
  431.     {
  432.         GetDItem(dlog, button, &type, &item, &box);
  433.         InsetRect(&box,-4,-4);
  434.         GetDItem(dlog, userItem, &type, &item, &userBox);
  435. #if USESROUTINEDESCRIPTORS
  436.         SetDItem(dlog,userItem,type,(Handle)&gDrawDefaultProcRD,&userBox);
  437. #else
  438.         SetDItem(dlog,userItem,type,(Handle)DrawDefaultProc,&userBox);
  439. #endif
  440.     }
  441.     
  442.     return userItem;
  443. } // InstallDefaultOutline 
  444.  
  445. //----------------------------------------------------------------------------------------
  446. // DrawActiveItemProc: 
  447. //
  448. //    Draw the thick square rectangle around the dialog item that accepts
  449. //    keyboard input (see the System 7 Chooser for an example).
  450. //----------------------------------------------------------------------------------------
  451. pascal void DrawActiveItemProc(DialogPtr dlog, short item)
  452. {
  453.     short            type;
  454.     Handle            itemHandle;
  455.     Rect            box;
  456.     PenState        saveState;
  457.     
  458.     GetPenState( &saveState );
  459.     GetDItem(dlog, item, &type, &itemHandle, &box);
  460.     PenNormal();
  461.     PenSize(2,2);
  462.     FrameRect(&box);
  463.     SetPenState( &saveState );
  464. } // DrawActiveItemProc 
  465.  
  466. //----------------------------------------------------------------------------------------
  467. // InstallActiveItemOutline: 
  468. //
  469. //    This function creates a useritem around the specified button & installs
  470. //    a drawing proc that draws the default border around it.
  471. //----------------------------------------------------------------------------------------
  472. short InstallActiveItemOutline(DialogPtr dlog, short button)
  473. {
  474.     short            userItem;
  475.     short            type;
  476.     Handle            item;
  477.     Rect            box;
  478.     Rect            userBox;
  479.     
  480.     userItem = AddNewUserItem( dlog );
  481.     if( userItem > 0 )
  482.     {
  483.         GetDItem(dlog, button, &type, &item, &box);
  484.         InsetRect(&box,-4,-4);
  485.         GetDItem(dlog, userItem, &type, &item, &userBox);
  486. #if USESROUTINEDESCRIPTORS
  487.         SetDItem(dlog,userItem,type,(Handle)&gDrawActiveItemProcRD,&userBox);
  488. #else
  489.         SetDItem(dlog,userItem,type,(Handle)DrawActiveItemProc,&userBox);
  490. #endif
  491.     }
  492.     
  493.     return userItem;
  494. } // InstallActiveItemOutline 
  495.  
  496. //----------------------------------------------------------------------------------------
  497. // DrawGreyTransformProc: 
  498. //
  499. //    Draw a grey transform to shade out a disabled control; this is most
  500. //    useful in conjunction with editText items, which do not normally draw
  501. //    with a disabled transform.
  502. //
  503. //    This function ASSUMES that the item after it is the one it should
  504. //    check for enabled/disabledness.
  505. //----------------------------------------------------------------------------------------
  506. pascal void DrawGreyTransformProc(DialogPtr dlog, short item)
  507. {
  508.     PenState        saveState;
  509.     short            userItem;
  510.     short            type;
  511.     Handle            itemHandle;
  512.     Rect            userBox;
  513.     
  514.     //
  515.     // Assume that the item before us is the one
  516.     // that we are obscuring; check it for being
  517.     // disabled
  518.     //
  519.     GetDItem(dlog, item - 1, &type, &itemHandle, &userBox);
  520.     if(type & itemDisable)
  521.     {
  522.         GetDItem(dlog, item, &type, &itemHandle, &userBox);
  523.     
  524.         GetPenState( &saveState );
  525.         PenNormal();
  526.         PenPat(&qd.gray);
  527.         PenMode(srcBic);
  528.         PaintRect(&userBox);
  529.         SetPenState( &saveState );
  530.     }
  531. } // DrawGreyTransformProc 
  532.  
  533. //----------------------------------------------------------------------------------------
  534. // InstallGreyTransform: 
  535. //
  536. //    Install 'DrawGreyTransformProc' around the specified user item.
  537. //----------------------------------------------------------------------------------------
  538. short InstallGreyTransform(DialogPtr dlog, short userItem)
  539. {
  540.     short            type;
  541.     Handle            item;
  542.     Rect            userBox;
  543.  
  544.     
  545.     GetDItem(dlog, userItem, &type, &item, &userBox);
  546. #if USESROUTINEDESCRIPTORS
  547.     SetDItem(dlog,userItem,type,(Handle)&gDrawGreyTransformProcRD,&userBox);
  548. #else
  549.     SetDItem(dlog,userItem,type,(Handle)DrawGreyTransformProc,&userBox);
  550. #endif
  551.     
  552.     return userItem;
  553. } // InstallGreyTransform 
  554.  
  555. //----------------------------------------------------------------------------------------
  556. // MoveOutline: 
  557. //    
  558. //    Move a userItem around the appropriate button.
  559. //    
  560. //    This function should be used in conjunction with
  561. //    InstallDefaultOutline to move the default button indicator
  562. //    from one button to another.  If you are using the
  563. //    CutPasteFilter with this routine, Return and Enter will
  564. //    automatically be translated to the correct button
  565. //----------------------------------------------------------------------------------------
  566. void MoveOutline(DialogPtr dlog, short userItem, short button)
  567. {
  568.     short            type;
  569.     Handle            item;
  570.     Rect            newBox;
  571.     Rect            oldBox;
  572.     
  573.     GetDItem(dlog, ((DialogPeek)dlog)->aDefItem, &type, &item, &oldBox);
  574.     InsetRect(&oldBox,-4,-4);
  575.     GetDItem(dlog, button, &type, &item, &newBox);
  576.     InsetRect(&newBox,-4,-4);
  577.     
  578.     //
  579.     // Erase the old box & invalidate the old and new
  580.     // locations to force a redraw
  581.     //
  582.     EraseRect( &oldBox );
  583.     InvalRect( &oldBox );
  584.     InvalRect( &newBox );
  585.     
  586.     //
  587.     // Remember where the default button outline moved to
  588.     //
  589.     ((DialogPeek)dlog)->aDefItem = button;
  590. } // MoveOutline 
  591.  
  592. //----------------------------------------------------------------------------------------
  593. // MoveActiveIndicator: 
  594. //    
  595. //    Move the active item indicator to another item.
  596. //    
  597. //    Note:    This routine erases and redraws the active item.
  598. //            It would be better to erase & invalidate, but that's
  599. //            pretty slow.
  600. //----------------------------------------------------------------------------------------
  601. void MoveActiveIndicator(DialogPtr dlog, short userItem, short button)
  602. {
  603.     short            type;
  604.     Handle            item;
  605.     Rect            box;
  606.     Rect            userBox;
  607.     RgnHandle        badRgn;
  608.     RgnHandle        tmpRgn;
  609.     
  610.     GetDItem(dlog, button, &type, &item, &box);
  611.     InsetRect(&box,-4,-4);
  612.     GetDItem(dlog, userItem, &type, &item, &userBox);
  613.     SetDItem(dlog, userItem, type, item, &box );
  614.     
  615.     //
  616.     // Erase the old active item indicator
  617.     //
  618.     badRgn = NewRgn();
  619.     tmpRgn = NewRgn();
  620.     RectRgn( badRgn, &userBox );
  621.     InsetRect( &userBox, 2, 2 );
  622.     RectRgn( tmpRgn, &userBox );
  623.     DiffRgn( badRgn, tmpRgn, badRgn );
  624.     EraseRgn( badRgn );
  625.     InvalRgn( badRgn );
  626.     DisposeRgn( badRgn );
  627.     DisposeRgn( tmpRgn );
  628.     
  629.     //
  630.     // Draw the new one
  631.     //
  632.     DrawActiveItemProc( dlog, userItem );
  633. } // MoveActiveIndicator 
  634.  
  635. //----------------------------------------------------------------------------------------
  636. // MoveDItem: 
  637. //    
  638. //    Move a Dialog Item.
  639. //    
  640. //    This is not _quite_ as easy as it sounds, because if the item
  641. //    is a control (such as a check box or radio button), MoveControl
  642. //    must also be called.
  643. //    
  644. //    NOTE:    This routine doesn't quite work, because it does not
  645. //            erase or redraw the item that moved unless it is
  646. //            a control.  Tsk tsk.
  647. //----------------------------------------------------------------------------------------
  648. void MoveDItem( DialogPtr dlog, short itemNumber, short h, short v )
  649. {
  650.     Handle            itemHandle;
  651.     short            itemType;
  652.     Rect            box;
  653.     
  654.     //
  655.     // Get some useful information about the DItem to move
  656.     //
  657.     GetDItem( dlog, itemNumber, &itemType, (Handle*)&itemHandle, &box );
  658.     
  659.     //
  660.     // Move the bounding box to the correct location
  661.     //
  662.     box.bottom += (v - box.top);
  663.     box.right += (h - box.left);
  664.     box.top = v;
  665.     box.left = h;
  666.     
  667.     //
  668.     // Set the bounding box of the item to move
  669.     //
  670.     SetDItem( dlog, itemNumber, itemType, (Handle)itemHandle, &box );
  671.     
  672.     //
  673.     // If the item is a control, call MoveControl
  674.     //
  675.     if( (itemType & ctrlItem) != 0 )
  676.     {
  677.         MoveControl( (ControlHandle)itemHandle, h, v );
  678.     }
  679. } // MoveDItem 
  680.  
  681. //----------------------------------------------------------------------------------------
  682. // SetItemHandle: 
  683. //    
  684. //    Set the item handle of a dialog item (particularly useful for
  685. //    useritems)
  686. //----------------------------------------------------------------------------------------
  687. void SetItemHandle( DialogPtr dlog, short whichItem, Handle newItem )
  688. {
  689.     short            type;
  690.     Handle            itemHandle;
  691.     Rect            box;
  692.     
  693.     GetDItem(dlog,whichItem,&type,&itemHandle,&box);
  694.     SetDItem(dlog,whichItem,type,newItem,&box);
  695. } // SetItemHandle 
  696.  
  697. //----------------------------------------------------------------------------------------
  698. // GetItemPoint: 
  699. //
  700. //    Returns the location of a given dialog item
  701. //----------------------------------------------------------------------------------------
  702. Point GetItemPoint( DialogPtr dlog, short itemNum )
  703. {
  704.     Point        loc;
  705.     short        type;
  706.     Handle        item;
  707.     Rect        box;
  708.     
  709.     GetDItem(dlog,itemNum, &type, &item, &box);
  710.     loc.h = box.left;
  711.     loc.v = box.top;
  712.     return( loc );
  713. } // GetItemPoint 
  714.  
  715. //----------------------------------------------------------------------------------------
  716. // DialogItemEnabled: 
  717. //    
  718. //    This routine is used by DrawDefaultProc and CutPasteFilter
  719. //    to determine if the default button is enabled
  720. //----------------------------------------------------------------------------------------
  721. Boolean DialogItemEnabled(DialogPtr dlog, short item)
  722. {
  723.     ControlHandle        buttonHandle = nil;
  724.     Rect                buttonBox;
  725.     short                type;
  726.  
  727.     GetDItem(dlog, item, &type, (Handle*)&buttonHandle, &buttonBox);
  728.     return ((type & itemDisable) == false);
  729. } // DialogItemEnabled 
  730.  
  731. //----------------------------------------------------------------------------------------
  732. // SetDialogItemDisableBit: 
  733. //
  734. //    Set or clear the 'itemDisable' bit of the dialog item
  735. //----------------------------------------------------------------------------------------
  736. void SetDialogItemDisableBit(DialogPtr dlog, short item, Boolean enable)
  737. {
  738.     Handle                itemHandle;
  739.     short                itemType;
  740.     Rect                box;
  741.     
  742.     GetDItem(dlog,item,&itemType,&itemHandle,&box);
  743.     itemType = (itemType & ~itemDisable) + (enable ? 0 : itemDisable);
  744.     SetDItem(dlog,item,itemType,itemHandle,&box);
  745. } // SetDialogItemDisableBit 
  746.  
  747. //----------------------------------------------------------------------------------------
  748. // EnableButton: 
  749. //
  750. //    This simple routine will enable or disable a button
  751. //----------------------------------------------------------------------------------------
  752. void EnableButton(DialogPtr dlog, short button,Boolean enable)
  753. {
  754.     ControlHandle        buttonHandle;
  755.     short                type;
  756.     Rect                box;
  757.     
  758.     SetDialogItemDisableBit(dlog, button, enable);
  759.     GetDItem(dlog,button,&type,(Handle*)&buttonHandle,&box);
  760.     HiliteControl(buttonHandle, enable ? 0 : 255);
  761.  
  762.     //
  763.     // Special checking:  are we enabling/disabling the
  764.     // default button?  If so, invalidate the area around
  765.     // the button so the default outline will redraw
  766.     //
  767.     if(button == ((DialogPeek)dlog)->aDefItem)
  768.     {
  769.         InsetRect(&box, -6, -6);
  770.         InvalRect(&box);
  771.     }
  772. } // EnableButton 
  773.  
  774. //----------------------------------------------------------------------------------------
  775. // EnabledTEItemsExist: 
  776. //
  777. //    Return true if there is at least one enabled TE item
  778. //----------------------------------------------------------------------------------------
  779. Boolean EnabledTEItemsExist(DialogPtr dlog)
  780. {
  781.     Boolean enabledTEExists = false;
  782.     short i;
  783.     
  784.     for(i=1; i < (**((short**)(((DialogPeek)dlog)->items)) + 1); ++i)
  785.     {
  786.         Handle                itemHandle;
  787.         short                itemType;
  788.         Rect                box;
  789.         
  790.         GetDItem(dlog,i,&itemType,&itemHandle,&box);
  791.         if(((itemType & itemDisable) == 0) && ((itemType & editText) == editText))
  792.             enabledTEExists = true;
  793.     }
  794.     
  795.     return enabledTEExists;
  796. }
  797.  
  798. //----------------------------------------------------------------------------------------
  799. // FindNextEnabledTEItem: 
  800. //
  801. //    Return the item # of the next enabled EditText item.
  802. //----------------------------------------------------------------------------------------
  803. short FindNextEnabledTEItem(DialogPtr dlog, short item)
  804. {
  805.     short searchFrom = item + 1;
  806.     short terminate = 0;
  807.     short itemFound = 0;
  808.     
  809.     //
  810.     // Look at every item in the list except for 'item'
  811.     //
  812.     while((searchFrom != item) && (searchFrom != terminate))
  813.     {
  814.         Handle                itemHandle;
  815.         short                itemType;
  816.         Rect                box;
  817.         
  818.         //
  819.         // When we get to the end, wrap around.  Set 'terminate'
  820.         // just in case 'item' has a bogus value
  821.         //
  822.         if(searchFrom > (**((short**)(((DialogPeek)dlog)->items)) + 1))
  823.         {
  824.             terminate = searchFrom;
  825.             searchFrom = 1;
  826.         }
  827.         
  828.         //
  829.         // Is this item an enabled textEdit item?
  830.         //
  831.         GetDItem(dlog,searchFrom,&itemType,&itemHandle,&box);
  832.         if(((itemType & itemDisable) == 0) && ((itemType & editText) == editText))
  833.         {
  834.             itemFound = searchFrom;
  835.             break;
  836.         }
  837.         ++searchFrom;
  838.     }
  839.     
  840.     return itemFound;
  841. }
  842.  
  843. //----------------------------------------------------------------------------------------
  844. // TabToNextEnabledTEItem: 
  845. //
  846. //    The dialog manager does not respect disabled TE items, so we need to have our
  847. //    own method of skipping to the next item when tab is pressed.
  848. //----------------------------------------------------------------------------------------
  849. void TabToNextEnabledTEItem(DialogPtr dlog)
  850. {
  851.     short itemToTabTo = FindNextEnabledTEItem(dlog, ((DialogPeek)dlog)->editField + 1);
  852.     if(itemToTabTo > 0)
  853.     {
  854.         SelIText(dlog, itemToTabTo, 0, 32767);
  855.     }
  856. }
  857.  
  858. //----------------------------------------------------------------------------------------
  859. // EnableTEItem: 
  860. //
  861. //    I wish this worked without extra support, but the dialog manager does not
  862. //    respect disabled editText items.  We have some convoluted code here that works
  863. //    in conjunction with the modless dialog handler code in the Window handler that
  864. //    allows us to disable editText items.
  865. //----------------------------------------------------------------------------------------
  866. void EnableTEItem(DialogPtr dlog, short item, Boolean enable)
  867. {
  868.     Handle                itemHandle;
  869.     short                itemType;
  870.     Rect                box;
  871.     
  872.     //
  873.     // First check to see if the TE item is going from
  874.     // enabled to disabled
  875.     //
  876.     GetDItem(dlog,item,&itemType,&itemHandle,&box);
  877.     if((enable == false) && ((itemType & itemDisable) == 0))
  878.     {
  879.         //
  880.         // Is this item the active TE item?
  881.         //
  882.         if(((DialogPeek)dlog)->editField == item - 1)
  883.         {
  884.             //
  885.             // Find an enabled editText item
  886.             //
  887.             short anEnabledItem = FindNextEnabledTEItem(dlog, item);
  888.             if(anEnabledItem == 0)
  889.             {
  890.                 //
  891.                 // Time to disable the last TE item
  892.                 //
  893.                 SelIText(dlog, item, 0, 0);
  894.                 TEDeactivate(((DialogPeek)dlog)->textH);
  895.             }
  896.             else
  897.             {
  898.                 //
  899.                 // I hope that this will activate the item whose
  900.                 // text is being selected, and deactivate 'item'
  901.                 //
  902.                 SelIText(dlog, anEnabledItem, 0, 32767);
  903.             }
  904.         }
  905.     }
  906.     
  907.     //
  908.     // Invalidate the area around the TE item in case
  909.     // InstallGreyTransform was called on a userItem
  910.     // around it.
  911.     // 
  912.     InsetRect(&box, -6, -6);
  913.     InvalRect(&box);
  914.     SetDialogItemDisableBit(dlog, item, enable);
  915.  
  916.     //
  917.     // We also have some work to do when enabling the first
  918.     // TE item (since we called TEDeactivate when we disable
  919.     // the last item, we'd better call TEActivate when we
  920.     // enable it)
  921.     //
  922.     if((enable == true) && ((itemType & itemDisable) != 0))
  923.     {
  924.         //
  925.         // If there is an enabled item somewhere, we don't
  926.         // have to worry about calling TEActivate because
  927.         // we did not call TEDeactivate.
  928.         //
  929.         if(FindNextEnabledTEItem(dlog, item) == 0)
  930.         {
  931.             //
  932.             // Fortunately, we don't need to worry about
  933.             // the fact that we may have disabled a
  934.             // "different" editText item, because there
  935.             // is only one TEHandle that is shared among
  936.             // all editable items.
  937.             // 
  938.             TEActivate(((DialogPeek)dlog)->textH);
  939.             SelIText(dlog, item, 0, 32767);
  940.         }
  941.     }
  942. } // EnableTEItem 
  943.  
  944. //----------------------------------------------------------------------------------------
  945. // GetCheckboxState: 
  946. //    
  947. //    Returns true of the checkbox is checked
  948. //----------------------------------------------------------------------------------------
  949. Boolean GetCheckboxState(DialogPtr dlog, short checkbox)
  950. {
  951.     Boolean state = false;
  952.     short itemType;
  953.     ControlHandle checkboxControl;
  954.     Rect box;
  955.     
  956.     GetDItem(dlog, checkbox, &itemType, (Handle*)&checkboxControl, &box);
  957.     if((itemType & (chkCtrl + ctrlItem)) == chkCtrl + ctrlItem)
  958.     {
  959.         state = GetCtlValue(checkboxControl);
  960.     }
  961.     
  962.     return state;
  963. } // GetCheckboxState 
  964.  
  965. //----------------------------------------------------------------------------------------
  966. // SetCheckboxState: 
  967. //    
  968. //    Check or uncheck a button
  969. //----------------------------------------------------------------------------------------
  970. void SetCheckboxState(DialogPtr dlog, short checkbox, Boolean check)
  971. {
  972.     short itemType;
  973.     ControlHandle checkboxControl;
  974.     Rect box;
  975.     
  976.     GetDItem(dlog, checkbox, &itemType, (Handle*)&checkboxControl, &box);
  977.     if((itemType & (chkCtrl + ctrlItem)) == chkCtrl + ctrlItem)
  978.     {
  979.         SetCtlValue(checkboxControl, check);
  980.     }
  981. } // SetCheckboxState 
  982.  
  983. //----------------------------------------------------------------------------------------
  984. // ToggleCheckboxState: 
  985. //    
  986. //    Reverse the state of a checkbox
  987. //----------------------------------------------------------------------------------------
  988. void ToggleCheckboxState(DialogPtr dlog, short checkbox)
  989. {
  990.     SetCheckboxState(dlog, checkbox, !GetCheckboxState(dlog, checkbox));
  991. } // ToggleCheckboxState 
  992.  
  993. //----------------------------------------------------------------------------------------
  994. // GetSelectedRadioButton: 
  995. //    
  996. //    Returns which of N radio buttons is selected
  997. //----------------------------------------------------------------------------------------
  998. short GetSelectedRadioButton(DialogPtr dlog, short firstRadio, short lastRadio)
  999. {
  1000.     short selected = firstRadio;
  1001.     Boolean state = false;
  1002.     short itemType;
  1003.     ControlHandle radioControl;
  1004.     Rect box;
  1005.     
  1006.     while((selected <= lastRadio) && (state == false))
  1007.     {
  1008.         GetDItem(dlog, selected, &itemType, (Handle*)&radioControl, &box);
  1009.         if((itemType & (radCtrl + ctrlItem)) == radCtrl + ctrlItem)
  1010.         {
  1011.             state = GetCtlValue(radioControl);
  1012.         }
  1013.         if(!state)
  1014.             ++selected;
  1015.     }
  1016.     
  1017.     if(!state)
  1018.         selected = 0;
  1019.     
  1020.     return state;
  1021. } // GetSelectedRadioButton 
  1022.  
  1023. //----------------------------------------------------------------------------------------
  1024. // SetSelectedRadioButton: 
  1025. //    
  1026. //    Set one of N radio buttons
  1027. //----------------------------------------------------------------------------------------
  1028. void SetSelectedRadioButton(DialogPtr dlog, short selectRadio, short firstRadio, short lastRadio)
  1029. {
  1030.     short itemType;
  1031.     ControlHandle checkboxControl;
  1032.     Rect box;
  1033.     short i;
  1034.     
  1035.     for(i=firstRadio; i<=lastRadio; ++i)
  1036.     {
  1037.         GetDItem(dlog, i, &itemType, (Handle*)&checkboxControl, &box);
  1038.         if((itemType & (radCtrl + ctrlItem)) == radCtrl + ctrlItem)
  1039.         {
  1040.             SetCtlValue(checkboxControl, i == selectRadio);
  1041.         }
  1042.     }
  1043. } // SetSelectedRadioButton 
  1044.  
  1045. //----------------------------------------------------------------------------------------
  1046. // FlashDlogItem: 
  1047. //    
  1048. //    Momentarily hilite a dialog button
  1049. //----------------------------------------------------------------------------------------
  1050. void FlashDlogItem( DialogPtr dlog, short itemNum )
  1051. {
  1052.     Handle        itemHandle;
  1053.     short        itemType;
  1054.     Rect        iRect;
  1055.     long        ticky;
  1056.     
  1057.     GetDItem(dlog,itemNum,&itemType,&itemHandle,&iRect);
  1058.     HiliteControl((ControlHandle)itemHandle,1);
  1059.     Draw1Control((ControlHandle)itemHandle);
  1060.     ticky = TickCount() + 10;
  1061.     do {} while( ticky > TickCount() );
  1062.     HiliteControl((ControlHandle)itemHandle,0);
  1063.     Draw1Control((ControlHandle)itemHandle);
  1064. } // FlashDlogItem 
  1065.  
  1066. //----------------------------------------------------------------------------------------
  1067. // CutPasteFilter: 
  1068. //    
  1069. //    This filter, when passed to ModalDialog, will allow the user to
  1070. //    cut, copy and paste by pressing command-X, command-C or command-V,
  1071. //    respectively.  It also checks if the cursor is over an editText
  1072. //    item, and if so, the cursor is changed into an IBeam.
  1073. //    
  1074. //    This procedure may be used as the filterProc of any dialog that
  1075. //    uses ModelDialog().  Note that this filter calls FlashDlogItem(),
  1076. //    above.  In all other respects, it is completely self-contained.
  1077. //    
  1078. //    This routine always translates command-. to button #2.
  1079. //    Your dialog box should have button #2 set up as a
  1080. //    'Cancel' button if you use this routine.
  1081. //----------------------------------------------------------------------------------------
  1082. pascal Boolean CutPasteFilter( DialogPtr dlog, EventRecord* event, short* item )
  1083. {
  1084.     DialogRecord    *dp = (DialogRecord *)dlog;
  1085.     TEHandle        te;
  1086.     Str255            Pstr;
  1087.     long            num;
  1088.     char            key;
  1089.     char            code;
  1090.     short            itemType = statText;
  1091.     short            itemNum;
  1092.     Handle            itemHandle;
  1093.     Point            mouse;
  1094.     Rect            tRect;
  1095.     
  1096.     te = dp->textH;
  1097.     
  1098.     //
  1099.     // Adjust the cursor to an iBeam or Arrow as appropriate
  1100.     //    
  1101.     GetMouse( &mouse );
  1102.     itemNum = FindDItem(dlog,mouse) + 1;
  1103.     if( itemNum > 0 )
  1104.         GetDItem(dlog,itemNum,&itemType,&itemHandle,&tRect);
  1105.     SetCursor( (itemType == editText) ? *GetCursor(iBeamCursor) : &qd.arrow);
  1106.     
  1107.     //
  1108.     // If the event is an update event, check to see
  1109.     // if it is for this dialog or for some other window
  1110.     //
  1111.     if( (event->what == updateEvt) )
  1112.     {
  1113.         //
  1114.         // If the update event is for this dialog box,
  1115.         // then draw the default button
  1116.         //
  1117.         if( StripAddress((DialogPtr)event->message) == StripAddress(dlog) )
  1118.         {
  1119.             //
  1120.             // The 'item' parameter is ignored, but we
  1121.             // don't have any better value to pass to
  1122.             // it than the item # of the default button
  1123.             //
  1124.             DrawDefaultProc(dlog, ((DialogPeek)dlog)->aDefItem );
  1125.         }
  1126.     }
  1127.     
  1128.     //
  1129.     // Is the event a key-down event?
  1130.     //
  1131.     if( (event->what == keyDown) || (event->what == autoKey) )
  1132.     {
  1133.         key  = (event->message & charCodeMask);
  1134.         code = (event->message &  keyCodeMask) >> 8;
  1135.         
  1136.         //
  1137.         // If F2, F3 or F4 (cut, copy or paste) are pressed,
  1138.         // forge a Command-X, C or V and handle the appropriate
  1139.         // command below.
  1140.         //
  1141.         switch( code )
  1142.         {
  1143.             case 120:
  1144.             {
  1145.                 event->modifiers |= cmdKey;
  1146.                 key = 'x';
  1147.                 break;
  1148.             }
  1149.             
  1150.             case  99:
  1151.             {
  1152.                 event->modifiers |= cmdKey;
  1153.                 key = 'c';
  1154.                 break;
  1155.             }
  1156.             
  1157.             case 118:
  1158.             {
  1159.                 event->modifiers |= cmdKey;
  1160.                 key = 'v';
  1161.                 break;
  1162.             }
  1163.         }
  1164.         
  1165.         //
  1166.         // Is the command key down?
  1167.         //
  1168.         if( event->modifiers & cmdKey )
  1169.         {
  1170.             switch( key )
  1171.             {
  1172.                 //
  1173.                 // Command-X, C and V are cut, copy and paste.
  1174.                 //
  1175.                 case 'x':
  1176.                 case 'c':
  1177.                 {
  1178.                     ZeroScrap();
  1179.                     if( key == 'x' )
  1180.                         DlgCut( dlog );
  1181.                     else
  1182.                         DlgCopy( dlog );
  1183.                     if( TEToScrap() != noErr )
  1184.                         SysBeep(120);
  1185.                     return true;
  1186.                 }
  1187.                                         
  1188.                 case 'v':
  1189.                 {
  1190.                     if( TEFromScrap() == noErr )
  1191.                         DlgPaste( dlog );
  1192.                     else
  1193.                         SysBeep(120);
  1194.                     return true;
  1195.                 }
  1196.                 
  1197.                 //
  1198.                 // Command-. cancels
  1199.                 //
  1200.                 case '.':
  1201.                 {
  1202.                     *item = 2;
  1203.                     FlashDlogItem( dlog, *item );
  1204.                     return true;
  1205.                 }
  1206.             }
  1207.             
  1208.             //
  1209.             // All other command-key combinations do nothing
  1210.             //
  1211.             event->what = nullEvent;
  1212.             return false;
  1213.         }
  1214.         
  1215.         //
  1216.         // If RETURN or ENTER was pressed, exit with
  1217.         // itemHit = ((DialogPeek)dlog)->aDefItem--but only if the
  1218.         // default button is enabled.
  1219.         //
  1220.         if( ((key == 13) || (key == 3)) && DialogItemEnabled(dlog,((DialogPeek)dlog)->aDefItem) )
  1221.         {
  1222.             *item = ((DialogPeek)dlog)->aDefItem;
  1223.             FlashDlogItem( dlog, *item );
  1224.             return true;
  1225.         }
  1226.         
  1227.         //
  1228.         // Swallow non-printing characters
  1229.         //
  1230.         if( (key < ' ') && (key != 8) && (key != 9) )
  1231.         {
  1232.             event->what = nullEvent;
  1233.             return false;
  1234.         }
  1235.     }
  1236.     return false;
  1237. } // CutPasteFilter 
  1238.